﻿#include<iostream>

#include"glframework/core.h"
#include"glframework/shader.h"
#include"errorCheck/errorCheck.h"
#include"application/application.h"
#define STB_IMAGE_IMPLEMENTATION
#include"application/stb_image.h"
#include"glframework/texture.h"
#include"application/camera/TrackBallController.h"
#include"application/camera/PerspectiveCamera.h"
#include"application/camera/OrthoCamera.h"
#include"application/camera/GameCameraController.h"
#include<iostream>
#include<string>
#include<fstream>
#include<sstream>

using namespace std;
/*
*	1、体验glGetError
*	2、将错误检查函数放到另外的cpp和h里面（子目录），然后编译成库并添加到父工程中
*	3、创建GL_CALL这个宏，便捷地进行gl函数错误检查
*	4、在CMAKE中添加全局预编译宏，来控制是否开启错误检查
*/
Shader* shader=nullptr;
Texture* texture = nullptr;


Camera* camera = nullptr;
CameraControl* cameraControl = nullptr;
glm::mat4 transform(1.0f);


glm::mat4 viewMetric(1.0f);
glm::mat4 orthoMatrix(1.0f);
glm::mat4 perspectiveMatrix(1.0f);

void onResize(int width, int height) {
	glViewport(0, 0, width, height);//窗口大小变化后改变视口大小
}
void onKey(int key,  int action, int mods) {
	cameraControl->onKey(key,action,mods);
}
void onMouseButton(int button, int action, int mods) {
	double x, y;
	myapp->getCursorPos(&x, &y);
	cameraControl->onMouse(button, action, (int)x,(int)y);

}
void onCursorPos(double xpos, double ypos) {
	cameraControl->onCursor(xpos, ypos);
}
void onScroll(double yoffset) {
	cameraControl->onScroll(yoffset);
}
void testInterLeavedBuffer() {
	//对于interleavedbuffer，即将不同种类的数据放到了一个VBO中的情况
	float pc[] = {//
0.0f,0.5f,0.0f,	 0.5f,0.7f,0.0f,	1.0f,0.0f,
0.3f,-0.2f,0.0f, 0.4f,-0.2f,0.0f,	0.5f,1.0f,
-0.3f,-0.2f,0.0f, 0.3f,0.5f,0.0f,	0.0f,0.0f,
	};	
	GLuint pcVBO;
	glGenBuffers(1, &pcVBO);
	glBindBuffer(GL_ARRAY_BUFFER, pcVBO);
	glBufferData(GL_ARRAY_BUFFER, sizeof(pc), pc, GL_STATIC_DRAW);

	GLuint vao = 0;
	glGenVertexArrays(1, &vao);
	glBindVertexArray(vao);


	glEnableVertexAttribArray(0);
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);//最后一个参数是指针类型，这其实是历史遗留问题，其实就是偏移量offset

	glEnableVertexAttribArray(1);
	glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));

	glEnableVertexAttribArray(2);
	glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 
		8 * sizeof(float), (void*)(6 * sizeof(float)));
	glBindVertexArray(0);
}
GLuint vao = 0;
void prepareEBO() { 
	float positions[] = {
	-0.8f,-0.8f,0.0f,
	0.8f,-0.8f,0.0f,
	0.8f,0.8f,0.0f,
	-0.8f,0.8f,0.0f
	};
	float uv[] = {
		0.0f,0.0f,
		1.0f,0.0f,
		1.0f,1.0f,
		0.0f,1.0f,
	};
	unsigned int indices[] = {
		0,1,2,
		2,3,0
	};
	//创建VBO
	GLuint vbo = 0;
	glGenBuffers(1, &vbo);
	glBindBuffer(GL_ARRAY_BUFFER, vbo);
	glBufferData(GL_ARRAY_BUFFER, sizeof(positions), positions, GL_STATIC_DRAW);
	GLuint uvVbo = 0;
	glGenBuffers(1, &uvVbo);
	glBindBuffer(GL_ARRAY_BUFFER, uvVbo);
	glBufferData(GL_ARRAY_BUFFER, sizeof(uv), uv, GL_STATIC_DRAW);
	//VAO 创建
	glGenVertexArrays(1, &vao);
	glBindVertexArray(vao);
	glBindBuffer(GL_ARRAY_BUFFER, vbo);
	glEnableVertexAttribArray(0);
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), 0);

	glBindBuffer(GL_ARRAY_BUFFER, uvVbo);
	glEnableVertexAttribArray(1);
	glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), 0);

	//创建EBO **EBO和VBO使用过程的唯一区别就是：GL_ARRAY_BUFFER和GL_ELEMENT_ARRAY_BUFFER的区别**
	GLuint ebo = 0;
	glGenBuffers(1, &ebo);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
	//加入ebo到当前vao
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
	//解绑VAO
	glBindVertexArray(0);
}
void doRotateTransfrom() {
	//构建一个旋转矩阵，绕着z轴旋转45度角
	//bug1：第二个参数旋转角度必须是一个float类型的，必须要在后面添加一个f
	//bug2：第二个参数接受的不是角度，而是弧度,使用glm::radians获得弧度时也需要注意要传float参数，
	// 不然由于重载，传入double类型时返回的也会是double
	transform = glm::rotate(transform, glm::radians(1.0f), glm::vec3(0.0, 0.0, 1.0));
}
void doTranslateTransform() {
	transform = glm::translate(glm::mat4(1.0f), glm::vec3(0.2f, 0.2f, 0.0f));//最后一个参数是各个坐标分量平移的DHC值。
}
void doScaleTransform() {
	transform = glm::scale(glm::mat4(1.0f), glm::vec3(0.5f, 0.5f, 1.0f));//最后一个参数是各个坐标缩放的倍数
}
void doRotateAfterTranslate() {//平移之后再旋转
	glm::mat4 rotate= glm::rotate(glm::mat4(1.0f), glm::radians(45.0f), glm::vec3(0.0, 0.0, 1.0));

	glm::mat4 translate= glm::translate(glm::mat4(1.0f), glm::vec3(0.2f, 0.2f, 0.0f));//最后一个参数是各个坐标分量平移的DHC值。
	//如果想要平移之后再旋转，应该是旋转的矩阵乘平移的矩阵，反过来就不对
	transform = rotate * translate;
	//不应该是这个顺序
	//transform = translate*rotate;
}
void prepareCamera() {
	float size = 3.0f;
	//camera = new OrthoCamera(-size, size, -size, size, size, -size);
	camera = new PerspectiveCamera(90.0f, (float)(myapp->getWidth() / myapp->getHeight()), 0.1f, 1000.0f);
	cameraControl = new GameCameraController();
	cameraControl->setCamera(camera);
	//lookat函数:生成一个viewMetric
	//eye：当前这个摄像机所在的位置
	//center:当前摄像机看向的那个点
	//up:穹顶向量，即摄像师拿着摄像机，头顶指向的方向
	//viewMetric = glm::lookAt(glm::vec3(0.5, 0.0, 0.5), glm::vec3(0.0,0.0,0.0), glm::vec3(0.0, 1.0f, 0.0));
}
void prepareOrtho() {
	//6个参数，分别是盒子的左右下上，还有最近near和最远far
	orthoMatrix = glm::ortho(-2.0f, 2.0f, -2.0f, 2.0f, 2.0f, -2.0f);
}
void preparePerspective() {
	//计算透视投影矩阵
	//参数一：fovy:Y轴方向的视张角，弧度单位
	//参数二：aspect：近平面（near平面）横纵比
	//参数三、四：近平面和远平面与摄像头的距离（没有负数）
	perspectiveMatrix = glm::perspective(glm::radians(90.0f), (float)myapp->getWidth() / myapp->getHeight(), 0.1f, 1000.0f);
}
void render() {//	//对于最后两个参数，这里near>far,因此转换后Z轴是指向内部
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
	//执行画布清理操作
	GL_CALL(glClear(GL_COLOR_BUFFER_BIT));//将这里的参数修改为无效的数字
	shader->begin();
	shader->setInt("sampler", 0);
	shader->setMetric4x4("transform", transform);
	shader->setMetric4x4("viewMetric", camera->getViewMatrix());
	shader->setMetric4x4("projectMatrix", camera->getProjectMatrix());
	glBindVertexArray(vao);  
	glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT,0);
	//glDrawArrays(GL_TRIANGLES, 0, 3);
	glBindVertexArray(0);
	shader->end(); 
}
int main()
{
	//向量
	glm::vec2 v0(0);
	glm::vec3 v1(0);
	glm::vec4 v2(0);
	//相加
	glm::vec4 v3 = v2 + glm::vec4(0);
	//点乘
	glm::vec4 v4 = v3 * v2;
	//叉乘(只能用在三维向量中)
	glm::vec3 vt0, vt1;
	glm::vec3 v5 = glm::cross(vt0,vt1);
		
	glm::mat3 m0(1.0);//初始化为单位矩阵
	glm::mat4 m1 = glm::identity<glm::mat4>();//也可以用函数来初始化一个单位矩阵
	glm::mat2 m2(1.0);
	glm::mat2x3 m3(1.0);//一个两行三列的矩阵
	cout << glm::to_string(m3)<<endl;




	if (!myapp->init(800, 600)) {
		return -1;
	}
	myapp->setResizeCallBack(onResize);
	myapp->setKeyBoardCallBack(onKey);
	myapp->setMouseButtonCallBack(onMouseButton);
	myapp->setCursorPosCallBack(onCursorPos);
	myapp->setScrollCallBack(onScroll);
	shader = new Shader("assert/shader/vertex.glsl", "assert/shader/fragment.glsl");
	texture = new Texture("assert/texture/mask.jpg", 0);

	prepareEBO();
	//doRotateTransfrom();
	//doTranslateTransform();
	doScaleTransform();
	//doRotateAfterTranslate();
	prepareCamera();
	//prepareOrtho();
	preparePerspective();
	while (myapp->update()) {
		cameraControl->update();
		render();
	}
	myapp->destroy();
	return 0;
}